﻿using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Threading;
using HttpWebAdapters;
using HttpWebAdapters.Adapters;

namespace TC.Vacation.Spider.Web
{
    internal class SynchronousWebRequest : ICsqWebResponse
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="SynchronousWebRequest"/> class.
        /// </summary>
        /// <param name="request">The request.</param>
        public SynchronousWebRequest(IHttpWebRequest request)
        {
            Request = request;
            Timeout = request.Timeout;
            UserAgent = request.UserAgent;
        }

        /// <summary>
        /// 信号量
        /// </summary>

        protected ManualResetEvent allDone = new ManualResetEvent(false);

        /// <summary>
        /// 请求对象
        /// </summary>

        public IHttpWebRequest Request
        {
            get;
            set;
        }

        /// <summary>
        /// Cookie保持对象
        /// </summary>
        private static CookieContainer CookieContainer;

        /// <summary>
        /// html流
        /// </summary>

        protected Stream ResponseStream { get; set; }

        /// <summary>
        /// 设置或获取编码
        /// </summary>

        public Encoding ResponseEncoding { get; set; }

        /// <summary>
        /// The _ web exception
        /// </summary>
        private WebException _WebException;

        /// <summary>
        /// 成功后的回调函数
        /// </summary>
        public Action<ICsqWebResponse> CallbackSuccess { get; set; }

        /// <summary>
        /// 失败后的回调函数
        /// </summary>
        public Action<ICsqWebResponse> CallbackFail { get; set; }

        /// <summary>
        /// 请求的url
        /// </summary>
        public string Url
        {
            get
            {
                return Request.RequestUri.AbsoluteUri;
            }
        }

        /// <summary>
        /// 请求开始时间
        /// </summary>
        public DateTime? Started { get; protected set; }

        /// <summary>
        /// 请求完成时间
        /// </summary>
        public DateTime? Finished { get; protected set; }

        /// <summary>
        /// 请求时出现的异常
        /// </summary>
        public WebException WebException
        {
            get
            {
                return _WebException;
            }
            protected set
            {
                _WebException = value;
            }
        }

        /// <summary>
        /// 一个响应对象
        /// </summary>

        public IHttpWebResponse Response
        {
            get;
            protected set;
        }

        /// <summary>
        /// 返回的HTML
        /// </summary>
        public string Html
        {
            get
            {
                using (var reader = new StreamReader(ResponseStream, ResponseEncoding))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// 标识请求是否成功
        /// </summary>
        public bool Success
        {
            get;
            protected set;
        }

        /// <summary>
        /// HTTP状态码
        /// </summary>
        public int HttpStatus
        {
            get
            {

                if (Response == null)
                {
                    return 0;
                }
                else
                {
                    return (int)Response.StatusCode;
                }
            }
        }

        /// <summary>
        /// HTTP状态标识字符串
        /// </summary>
        public string HttpStatusDescription
        {
            get
            {
                if (Response == null)
                {
                    return "";
                }
                else
                {
                    return Response.StatusDescription;
                }
            }
        }

        /// <summary>
        /// 请求出错时的异常信息
        /// </summary>
        public string Error
        {
            get
            {
                if (WebException == null)
                {
                    return "";
                }
                else
                {
                    return WebException.Message;
                }
            }
        }

        /// <summary>
        /// 标识请求是否完成
        /// </summary>
        /// <exception cref="System.InvalidOperationException">You can only set complete to True.</exception>
        public bool Complete
        {
            get
            {
                return Finished != null;
            }
            protected set
            {
                if (value == true)
                {
                    Finished = DateTime.Now;
                }
                else
                {
                    throw new InvalidOperationException("You can only set complete to True.");
                }
            }
        }

        /// <summary>
        /// 同步获取响应结果
        /// </summary>
        /// <returns></returns>
        public ManualResetEvent GetResponse()
        {
            Started = DateTime.Now;

            IHttpWebRequest req = Request;
            req.Timeout = Timeout * 1000;
            req.Headers["UserAgent"] = UserAgent;
            req.CookieContainer = Cookie;

            try
            {
                Response = req.GetResponse();
            }
            catch (WebException ex)
            {
                WebException = ex;
                Complete = true;
                Success = false;
                if (CallbackFail != null)
                {
                    CallbackFail(this);
                }
            }

            ResponseEncoding = CsqWebRequest.GetEncoding(Response) ?? Encoding.UTF8;

            ResponseStream = Response.ContentEncoding == "gzip" ?
                        new GZipStream(Response.GetResponseStream(), CompressionMode.Decompress) :
                        Response.GetResponseStream();

            if (ResponseStream != null)
            {
                Complete = true;
                Success = true;

                if (CallbackSuccess != null)
                {
                    CallbackSuccess(this);
                }
            }
            else
            {
                Complete = true;
                Success = false;
                if (CallbackFail != null)
                {
                    CallbackFail(this);
                }
            }
            allDone.Set();

            return allDone;
        }

        /// <summary>
        /// 请求唯一标识ID
        /// </summary>
        public object Id { get; set; }

        /// <summary>
        /// 请求配置项
        /// </summary>
        /// <exception cref="System.NotImplementedException">
        /// </exception>
        public ServerConfig Options
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// 请求超时--秒
        /// </summary>
        public int Timeout
        {
            get;
            set;
        }

        /// <summary>
        /// 浏览器标识
        /// </summary>
        public string UserAgent
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the web proxy.
        /// </summary>
        /// <value>
        /// The web proxy.
        /// </value>
        public IWebProxy WebProxy
        {
            get
            {
                return Request.Proxy;
            }
        }

        /// <summary>
        /// 抓取耗时
        /// </summary>
        /// <value>
        /// The spent.
        /// </value>
        public double Spent
        {
            get
            {
                TimeSpan? time = Finished - Started;
                return time.HasValue ? time.Value.TotalMilliseconds : 0;
            }
        }

        /// <summary>
        /// Gets the cookie.
        /// </summary>
        /// <value>
        /// The cookie.
        /// </value>
        public CookieContainer Cookie
        {
            get
            {
                if (Response != null && CookieContainer == null)
                {
                    CookieContainer = new System.Net.CookieContainer();
                    string cookiesExpression = Response.Headers["Set-Cookie"];
                    if (!string.IsNullOrEmpty(cookiesExpression))
                    {
                        Uri cookieUrl = new Uri(string.Format("{0}://{1}:{2}/",
                            Response.ResponseUri.Scheme,
                            Response.ResponseUri.Host,
                            Response.ResponseUri.Port));
                        CookieContainer.SetCookies(cookieUrl, cookiesExpression);
                    }
                }
                return CookieContainer ?? new CookieContainer();
            }
        }
    }
}
